﻿/*************************************************************************************

- CLR版本：        4.0.30319.42000
- 类 名 称：       SocketHelper
- 机器名称：       YTE
- 命名空间：       Common
- 文 件 名：       SocketHelper
- 创建时间：       2021/1/8 17:19:57
- 作    者：       YTE
- 说   明：
- 修改时间：
- 修 改 人：
  *************************************************************************************/

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using Server.Entity;

namespace Server.Utils
{
    public class SocketServerHelper
    {
        public Action<SendType, string> ReciveAction;
        public Action<string, string> LogAction;
        public Action<string> DisconnectAction;
        public Action<string, string, int, long, bool> SendProgressAction;
        public Dictionary<string, Socket> ClientSocketList;
       // private string _IP;
        private int _Port;
        private bool _isToFolder = false;
        private int _fileNum = 0;
        public ClientMsgModel ClientMsgModelInfo { get; set; }

        public List<Position> PositionList { get; set; } = new List<Position>();

        //public SocketServerHelper(string ip, int port)
        //{
        //    ClientSocketList = new Dictionary<string, Socket>();
        //    _IP = ip;
        //    _Port = port;
        //}
        public SocketServerHelper(int port)
        {
            ClientSocketList = new Dictionary<string, Socket>();
            _Port = port;
        }
        public bool IsConnected { get; private set; } = false;

        /// <summary>
        /// 启动监听
        /// </summary>
        public void Start()
        {
            try
            {
                IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Any, _Port);
                Socket socketWatch = new Socket(ipEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                socketWatch.Bind(ipEndPoint);
                #region 弃用
                //当点击开始监听的时候 在服务器端创建一个负责监IP地址跟端口号的Socket
                // Socket socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                //// 获取IP
                //  IPAddress ip = IPAddress.Parse(_IP);
                // //创建端口号
                //  IPEndPoint port = new IPEndPoint(ip, _Port);
                //// 监听
                // socketWatch.Bind(port);
                #endregion
                LogAction?.Invoke("监听成功", string.Empty);
                socketWatch.Listen(8);
                //新建线程，去接收客户端发来的信息
                Thread td = new Thread(AcceptMgs);
                td.IsBackground = true;
                td.Start(socketWatch);
                IsConnected = true;
            }
            catch (Exception ex)
            {
                LogAction?.Invoke(ex.Message, string.Empty);
                LogHelper.Error(ex);
            }
        }

        /// <summary>
        /// 接收客户端发送的信息
        /// </summary>
        /// <param name="o"></param>
        private void AcceptMgs(object o)
        {
            try
            {
                Socket socketWatc = (Socket)o;
                while (true)
                {
                    ////负责跟客户端通信的Socket
                    Socket socketSend = socketWatc.Accept();
                    string clientIP = socketSend.RemoteEndPoint.ToString().Split(':')[0];
                    //将远程连接的客户端的IP地址和Socket存入集合中
                    if (ClientSocketList.ContainsKey(clientIP))
                    {
                        ClientSocketList.Remove(clientIP);
                        DisconnectAction?.Invoke(clientIP);
                    }
                    ClientSocketList.Add(clientIP, socketSend);
                    ClientMsgModelInfo = new ClientMsgModel();
                  
                    string json = Newtonsoft.Json.JsonConvert.SerializeObject(ClientMsgModelInfo);
                    ReciveAction?.Invoke(SendType.对象, json);
                  //  LogAction?.Invoke(clientIP,"连接成功");
                    //新建线程循环接收客户端发来的信息
                    Thread td = new Thread(Recive);
                    td.IsBackground = true;
                    td.Start(socketSend);
                }
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
            }
        }

       

        /// <summary>
        /// 接收客户端发来的数据，并显示出来
        /// </summary>
        private void Recive(object o)
        {
            Socket socketSend = (Socket)o;
            try
            {
                while (true)
                {
                    //客户端连接成功后，服务器应该接受客户端发来的消息
                    if (socketSend == null)
                    {
                        LogAction?.Invoke(string.Empty,"请选择要发送的客户端");
                        continue;
                    }
                    byte[] buffer = new byte[1024 * 1024 * 5];
                    int r = socketSend.Receive(buffer);
                    if (r == 0)
                    {
                        break;
                    }
                    string strMsg = string.Empty;
                    switch (buffer[0])
                    {
                        case (int)SendType.对象:
                            strMsg = Encoding.UTF8.GetString(buffer, 1, r - 1);
                            ReciveAction?.Invoke(SendType.对象, strMsg);
                            break;
                        case (int)SendType.字符串:
                            strMsg = Encoding.UTF8.GetString(buffer, 1, r - 1);

                            ReciveAction?.Invoke(SendType.字符串, strMsg);
                            break;
                        default:
                            break;
                    }
                }
            }
            catch (Exception ex)
            {
                string disIp = socketSend.RemoteEndPoint.ToString().Split(':')[0];
                ClientSocketList.Remove(disIp);
                DisconnectAction?.Invoke(disIp);
                LogAction?.Invoke(disIp,"停止连接");
                LogHelper.Error(ex);
            }
        }
        /// <summary>
        /// 发送字符串
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="msg"></param>
        public void Send(string ip, string msg)
        {
            if (!ClientSocketList.ContainsKey(ip))
            {
                LogAction?.Invoke(ip,"客户端不存在");
                return;
            }
            Socket socket = ClientSocketList[ip];
            if (socket == null)
            {
                LogAction?.Invoke(ip,"客户端Socket对象为空");
                return;
            }
            byte[] buffer = Encoding.UTF8.GetBytes(msg);
            List<byte> byteList = new List<byte> {(int) SendType.字符串};
            byteList.AddRange(buffer.ToArray());
            socket.Send(byteList.ToArray());
        }
        /// <summary>
        /// 发送文件夹
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="folderPath"></param>
        public void SendFolder(string ip, string folderPath)
        {
            
            string[] files = Directory.GetFiles(folderPath);
            foreach (string item in files)
            {
                _fileNum++;
                _isToFolder = _fileNum == files.Length;
                SendFile(ip, item, folderPath);
                Thread.Sleep(1000);
            }
            _fileNum = 0;

        }

        /// <summary>
        /// 发送文件
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="filePath">文件名称</param>
        /// <param name="folderPath">文件夹名称</param>
        public void SendFile(string ip, string filePath, string folderPath)
        {
            if (!ClientSocketList.ContainsKey(ip))
            {
                LogAction?.Invoke(ip,"客户端不存在");
                return;
            }
            try
            {
                int sendSize = 0;
                string fileName = Path.GetFileName(filePath);
                Socket socket = ClientSocketList[ip];
                if (socket == null)
                {
                    LogAction?.Invoke(ip,"客户端Socket对象为空");
                    return;
                }

                //读取文档
                using (FileStream fsRead = new FileStream(filePath, FileMode.Open, FileAccess.Read))
                {
                    long length = fsRead.Length;

                    //第一步
                    string totalMsg = string.Format("{0}-{1}", fileName, length);
                    byte[] buffer = Encoding.UTF8.GetBytes(totalMsg);
                    List<byte> byteList = new List<byte> {(int) SendType.文件};
                    byteList.AddRange(buffer);
                    socket.Send(byteList.ToArray());

                    //第二步
                    byte[] filebuffer = new byte[1024 * 1024 * 5];     //5mb缓存 
                    SendProgressAction?.Invoke(ip,fileName, sendSize, length, _isToFolder);
                    //if (_fileNum == 1)
                    //{
                    //    LogAction?.Invoke("开始上传文件");
                    //    SendProgressAction?.Invoke(fileName, sendSize, length, _isToFolder);
                    //}
                    while (true)
                    {
                        int r = fsRead.Read(filebuffer, 0, filebuffer.Length);
                        if (r == 0) break;
                        sendSize += r;
                        socket.Send(filebuffer, 0, r, SocketFlags.None);
                        SendProgressAction?.Invoke(ip, fileName, sendSize, length, _isToFolder);
                        //Thread.Sleep(300);
                    }
                    
                    LogAction?.Invoke(ip,$"发送完成;{fileName}");
                 
                }
            }
            catch (Exception ex)
            {
                LogAction?.Invoke(ip,ex.Message);
                LogHelper.Error(ex);
            }
        }
    }
}
